package com.netease.nim.uikit.api

import android.util.Log
import com.hjq.toast.ToastUtils
import com.netease.nim.uikit.R
import com.netease.nim.uikit.api.model.main.OnlineStateChangeObserver
import com.netease.nim.uikit.impl.NimUIKitImpl
import com.netease.nimlib.sdk.*
import com.netease.nimlib.sdk.Observer
import com.netease.nimlib.sdk.auth.AuthService
import com.netease.nimlib.sdk.auth.LoginInfo
import com.netease.nimlib.sdk.event.EventSubscribeService
import com.netease.nimlib.sdk.event.EventSubscribeServiceObserver
import com.netease.nimlib.sdk.event.model.EventSubscribeRequest
import com.netease.nimlib.sdk.event.model.EventSubscribeResult
import com.netease.nimlib.sdk.event.model.NimOnlineStateEvent
import com.netease.nimlib.sdk.friend.FriendService
import com.netease.nimlib.sdk.friend.constant.VerifyType
import com.netease.nimlib.sdk.friend.model.AddFriendData
import com.netease.nimlib.sdk.msg.MsgService
import com.netease.nimlib.sdk.msg.MsgServiceObserve
import com.netease.nimlib.sdk.msg.SystemMessageService
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum
import com.netease.nimlib.sdk.msg.constant.SystemMessageType
import com.netease.nimlib.sdk.uinfo.UserService
import com.netease.nimlib.sdk.uinfo.constant.UserInfoFieldEnum
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.util.*

import com.netease.nimlib.sdk.chatroom.model.*
import com.netease.nimlib.sdk.chatroom.ChatRoomServiceObserver

import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage
import com.netease.nimlib.sdk.friend.FriendServiceObserve
import com.netease.nimlib.sdk.friend.model.Friend
import com.netease.nimlib.sdk.friend.model.FriendChangedNotify
import com.netease.nimlib.sdk.msg.SystemMessageObserver
import com.netease.nimlib.sdk.team.TeamService
import com.netease.nimlib.sdk.team.TeamServiceObserver
import com.netease.nimlib.sdk.team.constant.TeamFieldEnum
import com.netease.nimlib.sdk.team.constant.TeamMessageNotifyTypeEnum
import com.netease.nimlib.sdk.team.model.Team
import com.netease.nimlib.sdk.team.model.TeamMember
import com.netease.nimlib.sdk.uinfo.model.NimUserInfo
import www.wen.com.common.lib.extension.toast
import java.io.Serializable
import com.netease.nimlib.sdk.ResponseCode

import com.netease.nimlib.sdk.RequestCallbackWrapper

import com.netease.nimlib.sdk.NIMClient
import com.netease.nimlib.sdk.search.model.MsgIndexRecord
import www.wen.com.common.lib.extension.getString

import com.netease.nimlib.sdk.RequestCallback
import com.netease.nimlib.sdk.chatroom.ChatRoomService
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum
import com.netease.nimlib.sdk.msg.model.*
import com.netease.nimlib.sdk.team.model.IMMessageFilter
import www.wen.com.common.lib.data.entities.AitMessageEntity
import www.wen.com.common.lib.data.entities.TeamUnreadEntity
import www.wen.com.common.lib.data.entities.UnreadEntity
import www.wen.com.common.lib.extension.postObject
import www.wen.com.common.lib.helper.loading.KeyHelper
import kotlin.collections.HashSet


object NIMHelper {
    private const val TAG = "NimHelper"

    /**
     * [Deprecated]
     * 群组的EXTENSION,是否可以添加好友由客户端判断
     */
    const val BAN_ADD_FRIEND = "{\"canNotAddFriend\":1}"
    const val CAN_ADD_FRIEND = "{\"canNotAddFriend\":0}"

    /**
     * 在线离线的状态显示
     */
    const val ONLINE_STATUS = "在线"
    const val OFFLINE_STATUS = "离线"

    private val requestCallbackVoidWrapper = object : RequestCallbackWrapper<Void?>() {
        override fun onResult(code: Int, result: Void?, exception: Throwable?) {
            Log.d(TAG, "onResult: code:$code,result:$result,exception:$exception")
        }
    }

    /**
     * 默认登录回调
     */
    private val requestCallbackWrapper = object : RequestCallbackWrapper<LoginInfo?>() {
        override fun onResult(code: Int, result: LoginInfo?, exception: Throwable?) {
            Log.d(TAG, "onResult: code:$code,result:$result,exception:$exception")
            if (code == ResponseCode.RES_SUCCESS.toInt()) {
                toast("登录成功,account=${result?.account}")
                loginSuccessInit(result?.account)
            } else {
                toast("登录失败,code=$code,exception=$exception")
                //TODO 通过事件总线发送登录失败的事件
            }
        }
    }

    ////////////////////////////////////////////////////////
    ////////////////////// 未读数相关 //////////////////////
    ///////////////////////////////////////////////////////

    /**
     * 群组的Ait消息
     */
    var teamAitMessageMap = HashMap<String, HashSet<IMMessage>>()

    /**
     * 群组Ait消息总未读数
     */
    var teamAitMsgTotalUnreadCount = 0

    /**
     * 群组未读数信息
     */
    var teamUnreadCountMap = HashMap<String, Int>()

    /**
     * 群组总未读数
     */
    var teamTotalUnreadCount = 0

    /**
     * 私信总未读数
     */
    var p2pTotalUnreadCount = 0

    /**
     * 私信未读数信息
     */
    var p2pUnreadCountMap = HashMap<String, Int>()

    /**
     * 添加好友通知未读数
     */
    var addFriendUnreadCount = 0

    /**
     * 清空未读数
     */
    fun clearUnreadCount() {
        teamAitMessageMap.clear()
        teamAitMsgTotalUnreadCount = 0
        teamUnreadCountMap.clear()
        teamTotalUnreadCount = 0
        p2pTotalUnreadCount = 0
        p2pUnreadCountMap.clear()
        addFriendUnreadCount = 0
        postObject(KeyHelper.UNREAD_COUNT_UPDATE, true)
    }

    /**
     * 更新私信的未读数
     * @param contactId 私信id
     * @param unreadCount 私信的未读数
     */
    fun updateP2pUnreadCount(contactId: String, unreadCount: Int) {
        p2pTotalUnreadCount -= p2pUnreadCountMap[contactId] ?: 0
        p2pTotalUnreadCount += unreadCount
        p2pUnreadCountMap[contactId] = unreadCount
    }

    /**
     * 更新群组的未读数
     * @param contactId 群组id
     * @param unreadCount 群组的未读数
     */
    fun updateTeamUnreadCount(contactId: String, unreadCount: Int) {
//        teamTotalUnreadCount -= teamUnreadCountMap[contactId] ?: 0
//        teamTotalUnreadCount += unreadCount
        teamUnreadCountMap[contactId] = unreadCount
        teamTotalUnreadCount = 0
        teamUnreadCountMap.values.forEach { teamTotalUnreadCount += it }
        val entity = TeamUnreadEntity(contactId, unreadCount)
        postObject(KeyHelper.TEAM_UNREAD_KEY, entity)
    }

    /**
     * 更新群组的ait消息未读数
     * @param contactId 群组id
     * @param messageSet 群组的ait消息集合
     */
    fun updateTeamAitUnread(contactId: String, messageSet: HashSet<IMMessage>) {
        teamAitMsgTotalUnreadCount -= teamAitMessageMap[contactId]?.size ?: 0
        teamAitMessageMap[contactId] = messageSet
        teamAitMsgTotalUnreadCount += messageSet.size
        postObject(KeyHelper.AIT_MESSAGE, AitMessageEntity(contactId, messageSet))
    }

    /**
     * 添加群组的ait消息
     * @param message 需要加入的ait消息
     */
    fun addTeamAitMessage(message: IMMessage) {
        teamAitMsgTotalUnreadCount++
        var hashSet = teamAitMessageMap[message.sessionId]
        if (hashSet == null) {
            hashSet = hashSetOf()
        }
        hashSet.add(message)
        postObject(KeyHelper.AIT_MESSAGE, AitMessageEntity(message.sessionId, hashSet))
    }

    /**
     * 通知添加好友通知更新
     */
    fun updateAddFriendUnreadCount(): Int {
        p2pTotalUnreadCount -= addFriendUnreadCount
        // 不能重复账号，并且不能是回复添加好友信息
        val querySystemMessageByTypeBlock = querySystemMessageByTypeBlock()
        val addFriendUnreadSet = hashSetOf<String>()
        querySystemMessageByTypeBlock?.filter {
            if (isInBlackList(it.fromAccount)) {
                deleteSystemMessage(it.messageId)
            }
            it.content == getString(R.string.add_friend_msg) && it.type == SystemMessageType.AddFriend && it.isUnread && !isInBlackList(
                it.fromAccount
            )
        }?.forEach {
            addFriendUnreadSet.add(it.fromAccount)
        }
        addFriendUnreadCount = addFriendUnreadSet.size
        p2pTotalUnreadCount += addFriendUnreadCount
        postObject(KeyHelper.UNREAD_COUNT_UPDATE, true)
        postObject(
            KeyHelper.UNREAD_KEY, UnreadEntity(
                UnreadEntity.TYPE_ADD_FRIEND,
                addFriendUnreadCount
            )
        )
        return addFriendUnreadCount
    }

    ////////////////////////////////////////////////////////
    ////////////////////// 用户相关 //////////////////////
    ///////////////////////////////////////////////////////

    /**
     * 登录云信
     * @param account 云信账号account
     * @param token 云信账号token
     * @param callback 登录回调
     */
    fun login(
        account: String,
        token: String,
        callback: RequestCallback<LoginInfo?> = requestCallbackWrapper
    ) {
        NIMClient.getService(AuthService::class.java)
            .login(LoginInfo(account, token))
            .setCallback(callback)
    }

    /**
     * 登录云信成功后，初始化
     */
    fun loginSuccessInit(account: String?) {
        NimUIKit.setAccount(account)
        subscribeFriendsLoginStatus()
        observeFriendsLoginStatus()
    }

    /**
     * 注销登录云信
     */
    fun logout() {
        clearUnreadCount()
        NIMClient.getService(AuthService::class.java).logout()
    }

    /**
     * 获取云信登录状态
     */
    fun getLoginStatus(): StatusCode = NIMClient.getStatus()

    /**
     * 云信是否登录
     */
    fun isLogin(): Boolean = NIMClient.getStatus().value == StatusCode.LOGINED.value

    /**
     * 获取登录的云信账号
     */
    fun getUserAccount() = NimUIKit.getAccount()

    /**
     * 更新云信头像和昵称
     * @param userName 云信账号昵称
     * @param headImgUrl 云信账号头像
     * @param callback 更新回调
     */
    fun updateIMInfo(
        userName: String,
        headImgUrl: String,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        val fields: MutableMap<UserInfoFieldEnum, Any> = HashMap(1)
        fields[UserInfoFieldEnum.Name] = userName
        fields[UserInfoFieldEnum.AVATAR] = headImgUrl
        NIMClient.getService(UserService::class.java)
            .updateUserInfo(fields)
            .setCallback(callback)
    }

    /**
     * 根据昵称反查账号
     * @param nickName 昵称
     * @return 账号
     */
    fun searchAccountByName(nickName: String, callback: RequestCallback<List<String>?>?) {
        NIMClient.getService(UserService::class.java).searchAccountByName(nickName)
            .setCallback(callback)
    }

    /**
     * 检测是否为好友
     * @param account 用户账号
     */
    fun isMyFriend(account: String) =
        NIMClient.getService(FriendService::class.java).isMyFriend(account)

    /**
     * 发送消息。<br>
     * 如果需要更新发送进度，请调用{@link MsgServiceObserve#observeMsgStatus(com.netease.nimlib.sdk.Observer, boolean)}
     * @param message    带发送的消息体，由{@link MessageBuilder}构造
     * @param resend 如果是发送失败后重发，标记为true，否则填false
     * @param callback 回调
     */
    fun sendMessage(
        message: IMMessage,
        resend: Boolean = false,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        NIMClient.getService(MsgService::class.java)
            .sendMessage(message, resend)
            .setCallback(callback)
    }

    /**
     * 插入消息到本地数据库，且通知更新UI界面，但不发送到服务器端。发送一条可设置他人为发送方的本地消息给自己。<br>
     * 该接口将消息保存到数据库后，会通知到UI，此时会触发{@link MsgServiceObserve#observeReceiveMessage(Observer, boolean)}通知。
     * @param msg    待保存的消息对象
     * @param fromAccount 发送者ID
     */
    fun insertLocalMessage(msg: IMMessage, fromAccount: String) {
        NIMClient.getService(MsgService::class.java)
            .insertLocalMessage(msg, fromAccount)
    }

    /**
     * 获取最近联系人列表
     */
    fun getRecentContact(callback: RequestCallback<List<RecentContact>?>) {
        NIMClient.getService(MsgService::class.java)
            .queryRecentContacts()
            .setCallback(callback)
    }

    /**
     * 创建一条空的联系人会话
     * @param contactId   会话id ，对方帐号或群组id。
     * @param sessionType 会话类型
     * @param tag         会话tag ， eg:置顶标签（UIKit中的实现： RECENT_TAG_STICKY） ，用户参照自己的tag 实现即可， 如不需要，传 0 即可。<br/>
     * @param time        会话时间 ，单位为ms。
     * @param saveToDB    是否需要将会话保存在DB中，注意以下两点：<br/>
     *                    <b> &nbsp; &nbsp; &nbsp; &nbsp;1，如果已经存在相同的会话（contactId 、sessionType 一样），则不会保存在db中； <br/>
     *                    &nbsp;&nbsp; &nbsp; &nbsp; 2，如果之前不存在相同的会话，且needSaveToDB为true 会触发{@link MsgServiceObserve#observeRecentContact(Observer, boolean)}通知；
     *                    <b/>
     */
    fun createEmptyRecentContact(
        contactId: String,
        sessionType: SessionTypeEnum,
        tag: Long = 0,
        time: Long = System.currentTimeMillis(),
        saveToDB: Boolean = true
    ) = NIMClient.getService(MsgService::class.java)
        .createEmptyRecentContact(contactId, sessionType, tag, time, saveToDB)

    /**
     * 删除最近联系人记录，既删本地也删漫游。<br>
     * 调用该接口后，会触发[MsgServiceObserve#observeRecentContactDeleted(Observer, boolean)]通知
     * @param account
     * @param sessionType
     */
    fun deleteRecentContact2(account: String, sessionType: SessionTypeEnum) {
        NIMClient.getService(MsgService::class.java)
            .deleteRecentContact2(account, sessionType)
    }

    /**
     * 清除与指定用户的所有消息记录，且不在数据库记录此次操作
     * @param account     会话ID
     * @param sessionType 聊天类型
     */
    fun clearChattingHistory(account: String, sessionType: SessionTypeEnum) {
        NIMClient.getService(MsgService::class.java)
            .clearChattingHistory(account, sessionType)
    }

    /**
     * 从本地数据库中获取用户资料（同步接口）
     * @param account 要获取的用户账号
     * @return 用户资料
     */
    fun getUserInfo(account: String) =
        NIMClient.getService(UserService::class.java)
            .getUserInfo(account)

    /**
     * 从本地数据库中批量获取用户资料（同步接口）
     * @param accounts 要获取的用户帐号集合
     * @return 用户资料列表
     */
    fun getUserInfoList(accountList: List<String>) =
        NIMClient.getService(UserService::class.java)
            .getUserInfoList(accountList)

    /**
     * 从服务器获取用户资料（每次最多获取150个用户，如果量大，上层请自行分批获取）
     * @param accounts 要获取的用户帐号
     * @return InvocationFuture 可以设置回调函数。在用户资料存入数据库后就会回调。
     */
    fun fetchUserInfo(accountList: List<String>, callback: RequestCallback<List<NimUserInfo>>) {
        NIMClient.getService(UserService::class.java)
            .fetchUserInfo(accountList)
            .setCallback(callback)
    }

    /**
     * 获取黑名单列表
     */
    fun getBlackList() = NIMClient.getService(FriendService::class.java).blackList

    /**
     * 添加到黑名单
     * @param account 用户账号
     * @param callback 回调
     */
    fun addToBlackList(
        account: String,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        NIMClient.getService(FriendService::class.java)
            .addToBlackList(account)
            .setCallback(callback)
    }

    /**
     * 从黑名单移除
     * @param account 用户账号
     * @param callback 回调
     */
    fun removeFromBlackList(
        account: String,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        NIMClient.getService(FriendService::class.java)
            .removeFromBlackList(account)
            .setCallback(callback)
    }

    /**
     * 判断是否在黑名单内
     * @param account 用户账号
     */
    fun isInBlackList(account: String) =
        NIMClient.getService(FriendService::class.java).isInBlackList(account)

    /**
     * 获取免打扰列表
     */
    fun getMuteList() = NIMClient.getService(FriendService::class.java).muteList

    /**
     * 设置免打扰
     */
    fun setMessageNotify(
        account: String,
        checkState: Boolean,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        NIMClient.getService(FriendService::class.java)
            .setMessageNotify(account, checkState)
            .setCallback(callback)
    }

    /**
     * 判断是否免打扰
     */
    fun isMute(account: String) =
        NIMClient.getService(FriendService::class.java).isNeedMessageNotify(account)

    ////////////////////////////////////////////////////////
    ////////////////////// 群相关 //////////////////////
    ///////////////////////////////////////////////////////

    /**
     * 将所有的群组都添加进最近联系人中
     */
    fun addAllTeamToRecentContact() {
        getAllTeam(object : RequestCallbackWrapper<List<Team>?>() {
            override fun onResult(
                code: Int,
                result: List<Team>?,
                exception: Throwable?
            ) {
                if (code == ResponseCode.RES_SUCCESS.toInt() && result != null) {
                    result.forEach { team ->
                        createEmptyRecentContact(
                            team.id, SessionTypeEnum.Team
                        )
                    }
                }
            }
        })
    }

    /**
     * 踢出群聊
     * @param teamId 群ID
     * @param accountList 账号列表
     * @param callback 回调
     */
    fun removeMembersFromTeam(
        teamId: String,
        accountList: List<String>,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        NIMClient.getService(TeamService::class.java)
            .removeMembers(teamId, accountList)
            .setCallback(callback)
    }

    /**
     * 转让群主
     * @param teamId 群ID
     * @param account 转让账号
     * @param quit 转让后是否退群
     * @param callback 回调
     */
    fun transferTeam(
        teamId: String,
        account: String,
        quit: Boolean,
        callback: RequestCallback<List<TeamMember?>?>
    ) {
        NIMClient.getService(TeamService::class.java)
            .transferTeam(teamId, account, quit)
            .setCallback(callback)
    }

    /**
     * 更新用户的群昵称
     * @param teamId 群ID
     * @param nickName 群昵称
     */
    fun updateMyTeamNick(teamId: String, nickName: String) {
        NIMClient.getService(TeamService::class.java)
            .updateMyTeamNick(teamId, nickName)
    }

    /**
     * 更新群组资料
     * @param teamId 群ID
     * @param fieldsMap 待更新的所有字段的新的资料，其中值类型必须和field中定义的fieldType一致
     * @param callback 回调
     */
    fun updateTeamFields(
        teamId: String,
        fieldsMap: Map<TeamFieldEnum, Serializable>,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        NIMClient.getService(TeamService::class.java)
            .updateTeamFields(teamId, fieldsMap)
            .setCallback(callback)
    }

    /**
     * 通过群ID获取群
     * @param teamId 群ID
     */
    fun getTeam(teamId: String) =
        NIMClient.getService(TeamService::class.java).queryTeamBlock(teamId)

    /**
     * 同步获取所有群
     */
    fun getAllTeamBlock() =
        NIMClient.getService(TeamService::class.java).queryTeamListBlock()

    /**
     * 异步获取所有群
     */
    fun getAllTeam(callback: RequestCallback<List<Team>?>?) {
        NIMClient.getService(TeamService::class.java).queryTeamList()
            .setCallback(callback)
    }

    /**
     * 获取群员
     * @param teamId 群ID
     * @param callback 群成员
     */
    fun getTeamMembers(teamId: String, callback: RequestCallback<List<TeamMember>?>?) {
        NIMClient.getService(TeamService::class.java).queryMemberList(teamId).setCallback(callback);
    }

    /**
     * 查询群成员资料。（同步版本）
     * @param teamId  群ID
     * @param account 群成员帐号
     * @return 群成员信息
     */
    fun getTeamMember(teamId: String, account: String): TeamMember? =
        NIMClient.getService(TeamService::class.java)
            .queryTeamMemberBlock(teamId, account)

    /**
     * 同步方式获取群组的未读数集合（网易云信没有提供直接的接口）
     * @return key--云信群组id，value--未读数
     */
    fun getAllTeamUnreadCountBlock(): MutableMap<String, Int> {
        val teamUnreadCountList = mutableMapOf<String, Int>()
        val allTeam = getAllTeamBlock()
        allTeam.forEach {
            teamUnreadCountList[it.id] = NIMClient.getService(MsgService::class.java)
                .queryRecentContact(it.id, SessionTypeEnum.Team)?.unreadCount ?: 0
        }
        return teamUnreadCountList
    }

    /**
     * 获取群组的未读数集合（网易云信没有提供直接的接口）
     * @param teams 群组集合
     * @return key--云信群组id，value--未读数
     */
    fun getAllTeamUnreadCount(teams: List<Team>): MutableMap<String, Int> {
        val teamUnreadCountList = mutableMapOf<String, Int>()
        teams.forEach {
            val service = NIMClient.getService(MsgService::class.java)
            teamUnreadCountList[it.id] = service
                .queryRecentContact(it.id, SessionTypeEnum.Team)?.unreadCount ?: 0
        }
        return teamUnreadCountList
    }

    /**
     * 群消息免打扰
     * @param teamId 群ID
     * @param notifyType 消息通知类型
     * @param callback 回调
     */
    fun muteTeam(
        teamId: String,
        notifyType: TeamMessageNotifyTypeEnum = TeamMessageNotifyTypeEnum.Mute,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        NIMClient.getService(TeamService::class.java).muteTeam(teamId, notifyType)
            .setCallback(callback)
    }

    /**
     * 本地获取会话的PIN消息列表
     * @param sessionId 会话ID
     * @param sessionType 会话类型
     * @return PIN消息列表
     */
    fun queryMsgPinBlock(sessionId: String, sessionType: SessionTypeEnum): List<MsgPinDbOption> =
        NIMClient.getService(MsgService::class.java)
            .queryMsgPinBlock(sessionId, sessionType)

    /**
     * PIN一条消息
     * @param message 被PIN的消息
     * @param ext 扩展字段
     * @param callback 回调
     */
    fun addMsgPin(message: IMMessage, ext: String, callback: RequestCallback<Long?>) {
        NIMClient.getService(MsgService::class.java)
            .addMsgPin(message, ext)
            .setCallback(callback)
    }

    /**
     * 移除一条消息的PIN
     * @param message 被PIN的消息
     * @param ext 扩展字段
     * @param callback 回调
     */
    fun removeMsgPin(message: IMMessage, ext: String, callback: RequestCallback<Long?>) {
        NIMClient.getService(MsgService::class.java)
            .removeMsgPin(message, ext)
            .setCallback(callback)
    }

    /**
     * 同步会话的PIN信息
     * @param sessionType 会话类型
     * @param sessionId   会话ID
     * @param timeStamp   时间戳，同步时间戳以后的PIN
     * @param callback    回调
     */
    fun syncMsgPin(
        sessionType: SessionTypeEnum,
        sessionId: String,
        timeStamp: Long,
        callback: RequestCallback<MsgPinSyncResponseOptionWrapper?>
    ) {
        NIMClient.getService(MsgService::class.java)
            .syncMsgPin(sessionType, sessionId, timeStamp)
            .setCallback(callback)
    }

    /**
     * 更新群的禁止互加好友选项
     * @param teamId 群ID
     * @param isBanAddFriend 是否禁止互加好友
     * @param callback 回调
     */
    fun changeTeamAddFriend(
        teamId: String,
        isBanAddFriend: Boolean,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        NIMClient.getService(TeamService::class.java)
            .updateTeam(
                teamId, TeamFieldEnum.Extension,
                if (isBanAddFriend) CAN_ADD_FRIEND else BAN_ADD_FRIEND
            ).setCallback(callback)
    }

    ////////////////////////////////////////////////////////
    ////////////////////// 聊天室相关 //////////////////////
    ///////////////////////////////////////////////////////
//    2021/9/4 确定使用群聊，废弃聊天室
//
//    /**
//     * 进入聊天室
//     * @param roomData   聊天室基本数据（聊天室ID必填）
//     * @param retryCount 如果进入失败，重试次数
//     * @param callback 回调
//     */
//    fun enterChatRoomEx(
//        roomData: EnterChatRoomData,
//        retryCount: Int = 1,
//        callback: RequestCallback<EnterChatRoomResultData>
//    ) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .enterChatRoomEx(roomData, retryCount)
//            .setCallback(callback)
//    }
//
//    /**
//     * 离开聊天室
//     * @param roomId 聊天室ID
//     */
//    fun exitChatRoom(roomId: String) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .exitChatRoom(roomId)
//    }
//
//    /**
//     * 获取聊天室信息
//     * @param roomId 聊天室ID
//     * @param callback 回调
//     */
//    fun fetchRoomInfo(roomId: String, callback: RequestCallback<ChatRoomInfo?>) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .fetchRoomInfo(roomId)
//            .setCallback(callback)
//    }
//
//    /**
//     * 更新聊天室信息
//     * @param roomId             聊天室id
//     * @param chatRoomUpdateInfo 可更新的聊天室信息
//     * @param needNotify         是否通知
//     * @param notifyExtension    更新聊天室信息操作的扩展字段，这个字段会放到更新聊天室信息通知消息的扩展字段中
//     */
//    fun updateRoomInfo(
//        roomId: String,
//        chatRoomUpdateInfo: ChatRoomUpdateInfo,
//        needNotify: Boolean = false,
//        notifyExtension: Map<String, Any> = mapOf(),
//        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
//    ) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .updateRoomInfo(roomId, chatRoomUpdateInfo, needNotify, notifyExtension)
//            .setCallback(callback)
//    }
//
//    /**
//     * 分页获取聊天室成员
//     * @param roomId          聊天室id
//     * @param memberQueryType 成员查询类型。见[MemberQueryType]
//     * @param time            固定成员列表用updateTime,
//     *                        游客列表用进入enterTime，
//     *                        填0会使用当前服务器最新时间开始查询，即第一页，单位毫秒
//     * @param limit           条数限制
//     */
//    fun fetchRoomMembers(
//        roomId: String,
//        memberQueryType: MemberQueryType = MemberQueryType.NORMAL,
//        time: Long = 0,
//        limit: Int = 100,
//        callback: RequestCallback<List<ChatRoomMember>?>,
//    ) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .fetchRoomMembers(roomId, memberQueryType, time, limit)
//            .setCallback(callback)
//    }
//
//    /**
//     * 根据用户id获取聊天室成员信息
//     * @param roomId   聊天室id
//     * @param accounts 成员帐号列表
//     * @return InvocationFuture 可以设置回调函数。回调中返回成员信息列表
//     */
//    fun fetchRoomMembersByIds(
//        roomId: String,
//        accounts: List<String>,
//        callback: RequestCallback<List<ChatRoomMember>?>,
//    ) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .fetchRoomMembersByIds(roomId, accounts)
//            .setCallback(callback)
//    }
//
//    /**
//     * 获取聊天室的未读数集合（网易云信没有提供直接的接口）
//     * @param teams 聊天室集合
//     * @return key--云信群组id，value--未读数
//     */
//    fun getAllChatRoomUnreadCount(teams: List<String>): MutableMap<String, Int> {
//        val teamUnreadCountList = mutableMapOf<String, Int>()
//        teams.forEach {
//            val service = NIMClient.getService(MsgService::class.java)
//            teamUnreadCountList[it] = service
//                .queryRecentContact(it, SessionTypeEnum.ChatRoom)?.unreadCount ?: 0
//        }
//        return teamUnreadCountList
//    }
//
//    /**
//     * 添加/移出聊天室黑名单
//     * @param memberOption 请求参数，包含聊天室id，帐号id以及可选的扩展字段
//     * @param isAdd        true:添加, false:移出
//     * @param callback     回调
//     */
//    fun markChatRoomBlackList(
//        memberOption: MemberOption,
//        isAdd: Boolean = true,
//        callback: RequestCallback<ChatRoomMember>
//    ) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .markChatRoomBlackList(isAdd, memberOption)
//            .setCallback(callback)
//    }
//
//    /**
//     * 添加/移出聊天室禁言名单
//     * @param memberOption 请求参数，包含聊天室id，帐号id以及可选的扩展字段
//     * @param isAdd        true:添加, false:移出
//     * @param callback     回调
//     */
//    fun markChatRoomMutedList(
//        memberOption: MemberOption,
//        isAdd: Boolean = true,
//        callback: RequestCallback<ChatRoomMember>
//    ) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .markChatRoomMutedList(isAdd, memberOption)
//            .setCallback(callback)
//    }
//
//    /**
//     * 设置聊天室成员临时禁言
//     * @param needNotify   是否需要发送广播通知，true：通知，false：不通知
//     * @param duration     禁言时长,单位秒
//     * @param memberOption 请求参数，包含聊天室id，帐号id以及可选的扩展字段
//     * @param callback     回调
//     */
//    fun markChatRoomTempMute(
//        memberOption: MemberOption,
//        needNotify: Boolean = true,
//        duration: Long = 300,
//        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
//    ) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .markChatRoomTempMute(needNotify, duration, memberOption)
//            .setCallback(callback)
//    }
//
//    /**
//     * 设为/取消聊天室普通成员
//     * @param isAdd        true:设为, false:取消
//     * @param memberOption 请求参数，包含聊天室id，帐号id以及可选的扩展字段
//     * @param callback     回调
//     */
//    fun markNormalMember(
//        memberOption: MemberOption,
//        isAdd: Boolean = true,
//        callback: RequestCallback<ChatRoomMember>
//    ) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .markNormalMember(isAdd, memberOption)
//            .setCallback(callback)
//    }
//
//    /**
//     * 设为/取消聊天室管理员
//     * @param isAdd        true:设为, false:取消
//     * @param memberOption 请求参数，包含聊天室id，帐号id以及可选的扩展字段
//     * @param callback     回调
//     */
//    fun markChatRoomManager(
//        memberOption: MemberOption,
//        isAdd: Boolean = true,
//        callback: RequestCallback<ChatRoomMember>
//    ) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .markChatRoomManager(isAdd, memberOption)
//            .setCallback(callback)
//    }
//
//    /**
//     * 踢掉特定成员
//     * @param roomId          聊天室id
//     * @param account         踢出成员帐号。仅管理员可以踢；如目标是管理员仅创建者可以踢
//     * @param notifyExtension 被踢通知扩展字段，这个字段会放到被踢通知的扩展字段中
//     */
//    fun kickMember(
//        roomId: String,
//        account: String,
//        notifyExtension: Map<String, Any> = mapOf(),
//        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
//    ) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .kickMember(roomId, account, notifyExtension)
//            .setCallback(callback)
//    }
//
//    /**
//     * 更新本人在聊天室内的信息
//     * @param roomId               聊天室id
//     * @param chatRoomMemberUpdate 可更新的本人角色信息，扩展字段用来实现 是否允许好友申请
//     * @param needNotify           是否通知
//     * @param notifyExtension      更新聊天室信息扩展字段，这个字段会放到更新聊天室信息通知的扩展字段中,最大长度2k
//     */
//    fun updateMyRoomRole(
//        roomId: String,
//        chatRoomMemberUpdate: ChatRoomMemberUpdate,
//        needNotify: Boolean = true,
//        notifyExtension: Map<String, Any> = mapOf(),
//        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
//    ) {
//        NIMClient.getService(ChatRoomService::class.java)
//            .updateMyRoomRole(roomId, chatRoomMemberUpdate, needNotify, notifyExtension)
//            .setCallback(callback)
//    }

    ////////////////////////////////////////////////////////
    ////////////////////// 好友相关 //////////////////////
    ///////////////////////////////////////////////////////

    /**
     * 好友在线状态，key是云信账号
     */
    var allFriendsLoginStatus = mutableMapOf<String, Boolean>()

    /**
     * 获取好友的登录状态
     */
    fun getFriendLoginState(account: String) =
        NimUIKitImpl.getOnlineStateContentProvider()?.getDetailDisplay(account) ?: OFFLINE_STATUS

    /**
     * 获取当前账号(仅限好友)是否在线
     */
    fun accountIsOnline(account: String): Boolean {
        return getFriendLoginState(account) == ONLINE_STATUS
    }

    /**
     * 根据用户账号获取好友关系
     * @param account 用户账号
     * @return 该账号对应的好友关系
     */
    fun getFriend(account: String) =
        NIMClient.getService(FriendService::class.java).getFriendByAccount(account)

    /**
     * 获取我所有的好友帐号
     * @return 好友帐号集合
     */
    fun getAllFriend(): List<Friend>? =
        NIMClient.getService(FriendService::class.java).friends

    /**
     * 查询添加好友的通知(异步)
     * @param offset 数据库查询偏移条数
     * @param limit    数据库查询条数
     */
    fun querySystemMessageByType(
        types: List<SystemMessageType> = listOf(SystemMessageType.AddFriend),
        offset: Int = 0,
        limit: Int = 100,
        callback: RequestCallback<List<SystemMessage>>
    ) {
        NIMClient.getService(SystemMessageService::class.java)
            .querySystemMessageByType(types, offset, limit)
            .setCallback(callback)
    }

    /**
     * 查询添加好友的通知(同步)
     * @param offset 数据库查询偏移条数
     * @param limit    数据库查询条数
     */
    fun querySystemMessageByTypeBlock(
        types: List<SystemMessageType> = listOf(SystemMessageType.AddFriend),
        offset: Int = 0,
        limit: Int = 100,
    ): MutableList<SystemMessage>? {
        // 只查询“添加好友”类型的系统通知, 从头开始查询，查询3条
        return NIMClient.getService(SystemMessageService::class.java)
            .querySystemMessageByTypeBlock(types, offset, limit)
    }

    /**
     * 获取未读数总数
     */
    fun getTotalRecentUnreadCount() = NIMClient.getService(MsgService::class.java).totalUnreadCount

    /**
     * 查询指定类型的系统通知未读数总和（同步版本）
     * @param types 系统通知类型集合
     * @return 指定类型的系统通知未读数总和
     */
    fun querySystemMessageUnreadCountByType(
        types: List<SystemMessageType> = listOf(SystemMessageType.AddFriend)
    ) = NIMClient.getService(SystemMessageService::class.java)
        .querySystemMessageUnreadCountByType(types)

    /**
     * 删除一条系统通知
     * @param messageId 指定的系统通知ID
     */
    fun deleteSystemMessage(messageId: Long) {
        NIMClient.getService(SystemMessageService::class.java)
            .deleteSystemMessage(messageId)
    }

    /**
     * 将指定类型的系统通知设为已读
     * @param types 系统通知类型集合
     */
    fun resetSystemMessageUnreadCountByType(
        types: List<SystemMessageType> = listOf(SystemMessageType.AddFriend)
    ) {
        NIMClient.getService(SystemMessageService::class.java)
            .resetSystemMessageUnreadCountByType(types)
    }

    /**
     * 将所有系统通知设为已读，系统通知的未读消息总数将清零。
     */
    fun resetSystemMessageUnreadCount() {
        NIMClient.getService(SystemMessageService::class.java)
            .resetSystemMessageUnreadCount()
        updateAddFriendUnreadCount()
    }


    /**
     * 设置单条系统通知为已读
     * @param messageId 系统通知ID
     */
    fun setSystemMessageRead(messageId: Long) {
        NIMClient.getService(SystemMessageService::class.java)
            .setSystemMessageRead(messageId)
    }

    /**
     * 根据锚点和方向从本地消息数据库中查询消息历史。<br>
     * 根据提供的方向(direct)，查询比anchor更老（QUERY_OLD）或更新（QUERY_NEW）的最靠近anchor的limit条数据。<br>
     * 调用者可使用asc参数指定结果排序规则，结果使用time作为排序字段。<br>
     * 注意：查询结果不包含锚点。
     * @param anchor    查询锚点
     * @param direction 查询方向
     * @param limit     查询结果的条数限制
     * @param asc       查询结果的排序规则，如果为true，结果按照时间升序排列，如果为false，按照时间降序排列
     * @param callback  回调
     */
    fun queryMessageListEx(
        anchor: IMMessage?,
        direction: QueryDirectionEnum = QueryDirectionEnum.QUERY_OLD,
        limit: Int = 20,
        asc: Boolean = true,
        callback: RequestCallback<List<IMMessage>>
    ) {
        NIMClient.getService(MsgService::class.java)
            .queryMessageListEx(anchor, direction, limit, asc)
            .setCallback(callback)
    }

    /**
     * 从服务器拉取消息历史记录，可以指定查询的消息类型，结果不存本地消息数据库。
     * <p>
     * 以锚点anchor作为起始点（不包含锚点），根据direction参数，往前或往后查询由锚点到toTime之间的最多limit条消息。<br>
     * 查询范围由toTime和limit共同决定，以先到为准。如果到toTime之间消息大于limit条，返回limit条记录，如果小于limit条，返回实际条数。
     * 当已经查询到头时，返回的结果列表的size可能会比limit小
     * @param anchor    起始时间点的消息，不能为null。<br>
     *                  设置自定义锚点时，使用 {@link MessageBuilder#createEmptyMessage(String, SessionTypeEnum, long)} 创建一个空对象即可<br>
     * @param toTime    结束时间点单位毫秒
     * @param limit     本次查询的消息条数上限(最多100条)
     * @param direction 查询方向，QUERY_OLD按结束时间点逆序查询，逆序排列；QUERY_NEW按起始时间点正序起查，正序排列
     * @param msgTypes  消息类型，数组。消息类型仅支持 0:文本，1:图片，2:语音，3:视频，4:地理位置，5:通知，6:文件，10:提示，100:自定义，其它为非法参数
     * @param persist   通过该接口获取的漫游消息记录，要不要保存到本地消息数据库。
     * @param persistClear 是否保存被清除的消息到本地数据库，在persist==true时生效
     * @param imMessageFilter 过滤器回调，如果返回true则被忽略，即视为没有拉到这条消息
     * @return InvocationFuture
     */
    fun pullMessageHistoryExType(
        anchor: IMMessage? = null,
        toTime: Long = 0,
        limit: Int = 100,
        direction: QueryDirectionEnum = QueryDirectionEnum.QUERY_OLD,
        msgTypes: Array<MsgTypeEnum> = arrayOf(
            MsgTypeEnum.text,
            MsgTypeEnum.audio,
            MsgTypeEnum.image,
            MsgTypeEnum.video
        ),
        persist: Boolean = false,
        persistClear: Boolean = false,
        imMessageFilter: IMMessageFilter = IMMessageFilter { false },
        callback: RequestCallback<List<IMMessage>>
    ) {
        NIMClient.getService(MsgService::class.java)
            .pullMessageHistoryExType(
                anchor,
                toTime,
                limit,
                direction,
                msgTypes,
                persist,
                persistClear,
                imMessageFilter
            )
            .setCallback(callback)
    }

    /**
     * 检索所有会话，返回每个会话与检索串匹配的消息数及最近一条匹配的消息记录。（异步函数）
     * @param keyword 待检索的字符串
     * @param limit 最多返回多少条记录
     * @param callback 回调
     */
    fun searchAllMessage(
        keyword: String,
        limit: Int = 200,
        callback: RequestCallback<List<MsgIndexRecord>>
    ) {
        NIMClient.getService(MsgService::class.java)
            .searchAllSession(keyword, limit)
            .setCallback(callback)
    }

    /**
     * 更新消息。目前只能更新本地扩展字段LocalExtension
     * @param message 待更新的消息记录
     */
    fun updateIMMessage(message: IMMessage) {
        NIMClient.getService(MsgService::class.java).updateIMMessage(message)
    }

    /**
     * 搜索与关键字匹配的所有好友
     * @return 好友关系集合
     */
    fun searchFriendsByKeyword(keyword: String, callback: RequestCallback<List<Friend>>) {
        NIMClient.getService(FriendService::class.java)
            .searchFriendsByKeyword(keyword)
            .setCallback(callback)
    }

    /**
     * 加好友请求
     * @param account 云信账号
     * @param msg 好友请求附言
     * @param verifyType 请求方式
     */
    fun addFriend(
        account: String,
        msg: String = getString(R.string.add_friend_msg),
        verifyType: VerifyType = VerifyType.VERIFY_REQUEST,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        if (isMyFriend(account)) {
            toast(getString(R.string.already_friend))
        } else {
            NIMClient.getService(FriendService::class.java)
                .addFriend(AddFriendData(account, verifyType, msg))
                .setCallback(callback)
        }
    }

    /**
     * 回应好友请求
     * @param account 云信账号
     * @param agree 是否通过
     * @param callback 回调
     */
    fun addFriendRequest(
        account: String,
        agree: Boolean,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        NIMClient.getService(FriendService::class.java)
            .ackAddFriendRequest(account, agree)
            .setCallback(callback)
    }

    /**
     * 删除好友
     * @param account 云信账号
     * @param callback 回调
     */
    fun deleteFriend(
        account: String,
        callback: RequestCallback<Void?> = requestCallbackVoidWrapper
    ) {
        NIMClient.getService(FriendService::class.java).deleteFriend(account, true)
            .setCallback(callback)
    }

    /**
     * 获取所有好友账号
     */
    fun getAllFriendAccount(): MutableList<String> {
        val friendAccounts = NIMClient.getService(
            FriendService::class.java
        ).friendAccounts ?: mutableListOf()
        friendAccounts.forEach {
            allFriendsLoginStatus[it] = false
        }
        return friendAccounts
    }

    /**
     * 获取好友的未读数集合（网易云信没有提供直接的接口）
     * 需要实时更新需要通过 [observeRecentContactList]
     * @return key--云信账号，value--未读数
     */
    suspend fun getAllFriendUnreadCountList(): MutableMap<String, Int> {
        return withContext(Dispatchers.IO) {
            val friendUnreadCountList = mutableMapOf<String, Int>()
            val friendAccounts = getAllFriendAccount()
            friendAccounts.forEach {
                friendUnreadCountList[it] = NIMClient.getService(MsgService::class.java)
                    .queryRecentContact(it, SessionTypeEnum.P2P).unreadCount
            }
            return@withContext friendUnreadCountList
        }
    }

    /**
     * 订阅好友登录状态
     */
    fun subscribeFriendsLoginStatus() {
        val eventSubscribeRequest = EventSubscribeRequest()

        //订阅类型：在线状态
        eventSubscribeRequest.eventType = NimOnlineStateEvent.EVENT_TYPE
        //有效期30天
        eventSubscribeRequest.expiry = 2592000
        val allFriendAccount = getAllFriendAccount()
        Log.d(TAG, "subscribeFriendsLoginStatus: $allFriendAccount")

        /**
         * 每次调用接口最多只能订阅100个账号，数量较多需多次调用。在线状态事件订阅，每个accid最大有效订阅账号不超过3000个。
         */
        //分割后的数组
        val splitList = splitList(allFriendAccount, 100)
        splitList.forEach {
            //订阅对象：所有好友
            eventSubscribeRequest.publishers = it

            NIMClient.getService(EventSubscribeService::class.java)
                .subscribeEvent(eventSubscribeRequest)
                .setCallback(object : RequestCallbackWrapper<List<String?>?>() {
                    override fun onResult(
                        code: Int,
                        result: List<String?>?,
                        exception: Throwable?
                    ) {
                        if (code == ResponseCode.RES_SUCCESS.toInt()) {
                            if (result != null) {
                                // 部分订阅失败的账号。。。
                                Log.d(TAG, "onResult: $result")
                            }
                        } else {
                        }
                    }
                })
        }
    }

    /**
     * 检查在线状态是否订阅
     */
    fun checkSubscribeRequest() {
        val eventSubscribeRequest = EventSubscribeRequest()

        //订阅类型：在线状态
        eventSubscribeRequest.eventType = NimOnlineStateEvent.EVENT_TYPE
        //有效期30天
        eventSubscribeRequest.expiry = 2592000
        val allFriendAccount = getAllFriendAccount()

        /**
         * 每次调用接口最多只能订阅100个账号，数量较多需多次调用。在线状态事件订阅，每个accid最大有效订阅账号不超过3000个。
         */
        //分割后的数组
        val splitList = splitList(allFriendAccount, 100)
        splitList.forEach {
            //订阅对象：所有好友
            eventSubscribeRequest.publishers = it
            NIMClient.getService(EventSubscribeService::class.java)
                .querySubscribeEvent(eventSubscribeRequest)
                .setCallback(object : RequestCallbackWrapper<List<EventSubscribeResult?>>() {
                    override fun onResult(
                        code: Int,
                        result: List<EventSubscribeResult?>?,
                        exception: Throwable?
                    ) {
                        Log.d(TAG, "onResult: $code , $result , $exception")
                    }
                })
        }
    }

    ////////////////////////////////////////////////////////
    ////////////////////// 观察者相关 //////////////////////
    ///////////////////////////////////////////////////////

    /**
     * 用户登录状态事件观察者
     */
    fun observeFriendsLoginStatus() {
        checkSubscribeRequest()
        NIMClient.getService(EventSubscribeServiceObserver::class.java)
            .observeEventChanged({
                it.forEach { event ->
                    Log.d(TAG, "observeFriendsLoginStatus: event ${event.eventValue}")
                    if (NimOnlineStateEvent.isOnlineStateEvent(event)) {
                        //改变用户状态
                        val onlineStateEventValue =
                            NimOnlineStateEvent.getOnlineStateEventValue(event)
                        Log.d(TAG, "observeFriendsLoginStatus: $onlineStateEventValue")
                        allFriendsLoginStatus[event.publisherAccount] =
                            onlineStateEventValue == NimOnlineStateEvent.OnlineStateEventValue.Login
                    }
                }
            }, true)
    }

    /**
     * 最近联系人观察者
     * @param observer 观察者
     * @param register true--注册,false--注销
     */
    fun observeRecentContactList(
        register: Boolean = true,
        observer: Observer<List<RecentContact>>
    ) {
        NIMClient.getService(MsgServiceObserve::class.java)
            .observeRecentContact(observer, register)
    }

    /**
     * 注册/注销消息接收观察者。 <br>
     * 通知的消息列表中的消息不一定全是接收的消息，也有可能是自己发出去，比如其他端发的消息漫游过来，
     * 或者调用{@link MsgService#saveMessageToLocal(IMMessage, boolean)}后，notify参数设置为true，通知出来的消息。
     * @param observer 观察者， 参数为收到的消息列表，消息列表中的消息均保证来自同一个聊天对象。
     * @param register true为注册，false为注销
     */
    fun observeReceiveMessage(
        register: Boolean = true,
        observer: Observer<List<IMMessage>?>
    ) {
        NIMClient.getService(MsgServiceObserve::class.java)
            .observeReceiveMessage(observer, register)
    }

    /**
     * 注册/注销消息接收观察者。
     * @param observer 观察者，参数为收到的消息集合
     * @param register true为注册，false为注销
     */
    fun observeChatRoomMessage(
        register: Boolean = true,
        observer: Observer<List<ChatRoomMessage>>
    ) {
        NIMClient.getService(ChatRoomServiceObserver::class.java)
            .observeReceiveMessage(observer, register)
    }

    /**
     * 注册/注销系统消息接收事件观察者
     * @param observer 观察者， 参数为接收到的系统消息
     * @param register true为注册，false为注销
     */
    fun observeReceiveSystemMsg(register: Boolean = true, observer: Observer<SystemMessage>) {
        NIMClient.getService(SystemMessageObserver::class.java)
            .observeReceiveSystemMsg(observer, register)
    }

    /**
     * 注册/注销系统消息未读数变化事件观察者
     * @param observer 观察者， 参数当前的系统消息未读数
     * @param register true为注册，false为注销
     */
    fun observeUnreadCountChange(register: Boolean = true, observer: Observer<Int>) {
        NIMClient.getService(SystemMessageObserver::class.java)
            .observeUnreadCountChange(observer, register)
    }

    /**
     * 监听好友关系变化通知
     * @param observer 观察者，参数为收到的好友关系变化通知。
     * @param register true为注册监听，false为取消监听
     */
    fun observeFriendChangedNotify(
        register: Boolean = true,
        observer: Observer<FriendChangedNotify>
    ) {
        NIMClient.getService(FriendServiceObserve::class.java)
            .observeFriendChangedNotify(observer, register)
    }

    /**
     * 群资料变动观察者通知。新建群和群更新的通知都通过该接口传递
     * @param observer 观察者
     * @param register true--注册,false--注销
     */
    fun observeTeamUpdate(
        register: Boolean = true,
        observer: Observer<List<Team>>
    ) {
        NIMClient.getService(TeamServiceObserver::class.java)
            .observeTeamUpdate(observer, register)
    }

    /**
     * 移除群的观察者通知。自己退群，群被解散，自己被踢出群时，会收到该通知
     * @param observer 观察者, 参数为被移除的群资料，此时群的isMyTeam接口返回false
     * @param register true--注册,false--注销
     */
    fun observeTeamRemove(
        register: Boolean = true,
        observer: Observer<Team>
    ) {
        NIMClient.getService(TeamServiceObserver::class.java)
            .observeTeamRemove(observer, register)
    }

    /**
     * 用户在线状态监听
     */
    fun observeOnlineStateChange(
        register: Boolean,
        onlineStateChangeObserver: OnlineStateChangeObserver
    ) {
        NimUIKitImpl.getOnlineStateChangeObservable()
            .registerOnlineStateChangeListeners(onlineStateChangeObserver, register)
    }

    /**
     * 根据长度分割数组
     * @param totalList 原数组
     * @param groupSize 分割长度
     */
    private fun splitList(
        totalList: List<String>,
        groupSize: Int
    ): List<List<String>> {
        val length = totalList.size
        // 计算可以分成多少组
        val num = (length + groupSize - 1) / groupSize
        val newList: MutableList<List<String>> = ArrayList(num)
        for (i in 0 until num) {
            // 开始位置
            val fromIndex = i * groupSize
            // 结束位置
            val toIndex = if ((i + 1) * groupSize < length) (i + 1) * groupSize else length
            newList.add(totalList.subList(fromIndex, toIndex))
        }
        return newList
    }

}